package grpc

import (
	"context"
	"crypto/tls"
	"errors"
	"gitee.com/zxs-micro/zxs-micro-common/log"
	"google.golang.org/grpc/credentials"
	"net"
	"time"
)

var (
	ErrClientHandshakeNotImplemented = errors.New("grpc/cerds.go: client handshakes are not implemented with serverCreds")
	ErrServerHandshakeNotImplemented = errors.New("grpc/cerds.go: server handshakes are not implemented with clientCreds")
	ErrOverrideHostnameNotSupported  = errors.New("grpc/cerds.go: OverrideServerName is not supported")
)

type serverCreds struct {
	serverConfig *TLSConfig
}

func (sc *serverCreds) ClientHandshake(context.Context, string, net.Conn) (net.Conn, credentials.AuthInfo, error) {
	return nil, nil, ErrClientHandshakeNotImplemented
}

// ServerHandshake does the authentication handshake for servers.
func (sc *serverCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
	serverConfig := sc.serverConfig.Config()

	conn := tls.Server(rawConn, &serverConfig)
	start := time.Now()
	if err := conn.Handshake(); err != nil {
		log.Log.Errorf("Server TLS handshake failed in %s with error %s", time.Since(start), err)
		return nil, nil, err
	}
	log.Log.Debugf("Server TLS handshake completed in %s", time.Since(start))
	return conn, credentials.TLSInfo{State: conn.ConnectionState()}, nil
}

// Info provides the ProtocolInfo of this TransportCredentials.
func (sc *serverCreds) Info() credentials.ProtocolInfo {
	return credentials.ProtocolInfo{
		SecurityProtocol: "tls",
		SecurityVersion:  "1.2",
	}
}

// Clone makes a copy of this TransportCredentials.
func (sc *serverCreds) Clone() credentials.TransportCredentials {
	config := sc.serverConfig.Config()
	serverConfig := NewTLSConfig(&config)
	return &serverCreds{
		serverConfig: serverConfig,
	}
}

// OverrideServerName overrides the server name used to verify the hostname
// on the returned certificates from the server.
func (sc *serverCreds) OverrideServerName(string) error {
	return ErrOverrideHostnameNotSupported
}
